﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;

namespace Technullogy
{
    class DirectorySync
    {
        #region Properties
        private static List<String> _directories;
        public static List<String> Directories
        {
            get
            {
                if (_directories == null)
                    _directories = new List<String>();
                return _directories;
            }
            set
            {
                _directories = value;
            }
        }

        private static List<String> _localDirectories;
        public static List<String> LocalDirectories
        {
            get
            {
                if (_localDirectories == null)
                    _localDirectories = LoadDirectories(TechnullogyConfiguration.LocalDirectory);

                return _localDirectories;
            }
        }

        private static List<String> _remoteDirectories;
        public static List<String> RemoteDirectories
        {
            get
            {
                if (_remoteDirectories == null)
                    _remoteDirectories = LoadDirectories(TechnullogyConfiguration.RemoteDirectory);

                return _remoteDirectories;
            }
        }
        #endregion

        #region Methods
        static void Main(String[] args)
        {
            DateTime start = DateTime.Now;

            if (TechnullogyConfiguration.CopyLocalToRemote || TechnullogyConfiguration.CopyRemoteToLocal)
            {
                TechnullogyLogging.LogDirectorySyncStarted(start);

                if (TechnullogyConfiguration.CopyLocalToRemote)
                {
                    TechnullogyLogging.IsLocalToRemote = true;
                    CopyLocalToRemote();
                    TechnullogyLogging.LogCopyStats();
                }

                if (TechnullogyConfiguration.CopyRemoteToLocal)
                {
                    TechnullogyLogging.IsLocalToRemote = false;
                    CopyRemoteToLocal();
                    TechnullogyLogging.LogCopyStats();
                }

                TechnullogyLogging.LogDirectorySyncFinished(start, DateTime.Now);
            }





            start = DateTime.Now;
            if (TechnullogyConfiguration.DeleteLocalEmptyDirectories || TechnullogyConfiguration.DeleteRemoteEmptyDirectories)
            {
                TechnullogyLogging.LogDirectoryDeleteStarted(start);

                List<String> emptyDirs;
                if (TechnullogyConfiguration.DeleteLocalEmptyDirectories)
                {
                    TechnullogyLogging.IsLocalToRemote = true;
                    emptyDirs = EmptyDirectory.GetEmptyDirectories(TechnullogyConfiguration.LocalDirectory);
                    EmptyDirectory.DeleteEmptyDirectories(emptyDirs);
                    TechnullogyLogging.LogDeleteStats();
                }

                if (TechnullogyConfiguration.DeleteRemoteEmptyDirectories)
                {
                    TechnullogyLogging.IsLocalToRemote = false;
                    emptyDirs = EmptyDirectory.GetEmptyDirectories(TechnullogyConfiguration.RemoteDirectory);
                    EmptyDirectory.DeleteEmptyDirectories(emptyDirs);
                    TechnullogyLogging.LogDeleteStats();
                }

                TechnullogyLogging.LogDirectoryDeleteFinished(start, DateTime.Now);
            }
        }

        private static void CopyLocalToRemote()
        {
            Directories = new List<String>();

            TechnullogyLogging.LogSyncStart(TechnullogyConfiguration.LocalDirectory, TechnullogyConfiguration.RemoteDirectory);

            CopyFiles(TechnullogyConfiguration.LocalDirectory, TechnullogyConfiguration.RemoteDirectory);

            SyncDirectories(LocalDirectories, TechnullogyConfiguration.LocalDirectory, TechnullogyConfiguration.RemoteDirectory);
        }

        private static void CopyRemoteToLocal()
        {
            Directories = new List<String>();

            TechnullogyLogging.LogSyncStart(TechnullogyConfiguration.RemoteDirectory, TechnullogyConfiguration.LocalDirectory);

            CopyFiles(TechnullogyConfiguration.RemoteDirectory, TechnullogyConfiguration.LocalDirectory);

            SyncDirectories(RemoteDirectories, TechnullogyConfiguration.RemoteDirectory, TechnullogyConfiguration.LocalDirectory);
        }

        private static void CopyFiles(String source, String destination)
        {
            var files = Directory.GetFiles(source);
            foreach (var file in files)
            {
                String fileToCheck = Path.Combine(destination, Path.GetFileName(file));

                if (TechnullogyConfiguration.FileTypesToExclude.Contains(Path.GetExtension(file).ToLower()))
                    TechnullogyLogging.LogFileSkipped(fileToCheck);
                else if (!File.Exists(fileToCheck))
                {
                    TechnullogyLogging.LogFileCopy(file, fileToCheck);
                    File.Copy(file, fileToCheck);
                }
                else if (TechnullogyConfiguration.OverwriteDestinationIfSourceIsLarger)
                    OverwriteFile(file, fileToCheck);
                else
                    TechnullogyLogging.LogFileExists(file);
                
            }
        }

        public static List<String> LoadDirectories(String dirPath)
        {
            TechnullogyLogging.LogLoadDirectories(dirPath);
            foreach (var item in Directory.GetDirectories(dirPath))
            {
                Directories.Add(item);
                LoadDirectories(item);
            }

            return Directories;
        }

        private static void SyncDirectories(List<String> source, String sourceRoot, String destinationRoot)
        {
            foreach (var directory in source)
            {
                String pathToCheck = ReplaceRoot(directory, sourceRoot, destinationRoot);
                if (!Directory.Exists(pathToCheck))
                {
                    TechnullogyLogging.LogDirectoryCreation(directory);
                    Directory.CreateDirectory(pathToCheck);
                }
                else
                    TechnullogyLogging.LogDirectoryExists(directory);

                CopyFiles(directory, pathToCheck);
            }
        }

        private static void OverwriteFile(String source, String destination)
        {
            FileInfo sourceFile = new FileInfo(source);
            FileInfo destinationFile = new FileInfo(destination);

            if (sourceFile.Length > destinationFile.Length)
            {
                TechnullogyLogging.LogOverwritingFile(source, destination, sourceFile.Length, destinationFile.Length);

                try
                {
                    TechnullogyLogging.LogFileCopy(source, destination);
                    File.Copy(source, destination, true);
                }
                catch (Exception ex)
                {
                    TechnullogyLogging.LogException(ex);
                }
            }
            else
                TechnullogyLogging.LogFileExists(source);
        }

        private static String ReplaceRoot(String item, String sourceRoot, String destinationRoot)
        {
            return item.Replace(sourceRoot, destinationRoot);
        }
        #endregion
    }
}